class KVue{
  constructor(options){
    /* 生命周期beforeCreated */
    options.beforeCreat && options.beforeCreat.call(this);
    /* 数据缓存 */
    this.$options = options;
    this.$data = options.data;
    this.$methods = options.methods;
    this.$computed = options.computed;
    /* observe data */
    this.observe(this.$data);
    /* init Event */
    this.initEvent(this.$methods);
    /* 生命周期created */
    options.created && options.created.call(this);
    /* el */
    if (options.el) {
      this.$el = options.el;
      new Compile(this.$el, this, options);
    }
  }
  $mount(){
    if (this.$el) return;
    new Compile(this.$el, this);
  }
  observe(data){
    if(!data || typeof data !== 'object') return;
    Object.keys(data).forEach(key => {
      // 给对象里面的属性修改get、set方法 
      this.defineData(data, key, data[key]);
      // 把data中的属性代理到Vue实例上
      this.proxyData(key);
    });
  }
  defineData(obj, key, val) {
    this.observe(val);
    // 每一个对象都会创建一个dep实例，每一个dep实例维护着多个依赖watcher
    const dep = new Dep();

    Object.defineProperty(obj, key, {
      get(){
        // 在Watcher中会有一段代码 this.xxx;
        // 这样等于把watcher维护到了this.xxx对应的dep中
        Dep.target && dep.addDep(Dep.target);
        return val;
      },
      set(newVal){
        if (val === newVal) return;
        val = newVal;
        // set的时候通知所有依赖，执行更新
        dep.notify();
      }
    });
  }
  initEvent(methods){
    if(!methods || typeof methods !== 'object') return;
    Object.keys(methods).forEach(key => {
      this[key] = this.$methods[key].bind(this);
    });
  }
  proxyData(key){
    Object.defineProperty(this, key, {
      get(){
        return this.$data[key];
      },
      set(newVal){
        this.$data[key] = newVal;
      }
    });
  }
}

/**
 * 1、存放若干个依赖，用数组维护
 * 2、有一个添加依赖的方法，直接往数组中push
 * 3、有一个通知方法，遍历所有依赖，执行依赖中的update方法
 * 4、一个属性可能有多个依赖
 */
class Dep{
  constructor(){
    this.deps = [];
  }
  addDep(watcher){
    this.deps.push(watcher);
  }
  notify(){
    this.deps.forEach(watcher => {
      watcher.update();
    })
  }
}

/**
 * 1、接收参数vm,key,callback
 * 2、在constructor中先给Dep的target赋值为当前的Watcher
 * 3、vm[key]触发属性的getter方法，把这个Watcher添加到属性对应的dep中
 * 4、update方法
 */
class Watcher{
  constructor(vm, key, cb) {
    this.vm = vm;
    this.key = key;
    this.cb = cb;
    // 把当前实例指定为Dep的静态属性target
    Dep.target = this;
    vm[key];  // 触发getter，添加依赖
    Dep.target = null;
  }
  update(){
    this.cb.call(this.vm, this.vm[this.key]);
  }
}